﻿using System;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Resources;
using System.Windows.Interop;

namespace Songhay.Silverlight.ApplicationLoader.Views
{
    using Models;

    /// <summary>
    /// The container for the initial payload.
    /// </summary>
    public partial class UserControlOne : UserControl
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="UserControlOne"/> class.
        /// </summary>
        public UserControlOne()
        {
            InitializeComponent();

            this._params = new LoaderInfo(Application.Current.Host.InitParams);

            try
            {
                var client = new WebClient();

                client.OpenReadCompleted +=
                    new OpenReadCompletedEventHandler(this.LoadCompleted);
                client.DownloadProgressChanged +=
                    new DownloadProgressChangedEventHandler(this.LoadProgressChanged);
                client.OpenReadAsync(new Uri(this._params.XapPath, UriKind.RelativeOrAbsolute));
            }
            catch(Exception e)
            {
                this.LoadFailed(e);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UserControlOne"/> class.
        /// </summary>
        /// <param name="host">The host.</param>
        public UserControlOne(SilverlightHost host)
            : this()
        {
            this._silverlightHost = host;
        }

        internal void LoadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if(e.Error != null)
            {
                this.LoadFailed(e.Error);
                return;
            }

            try
            {
                Assembly silverlightApplication = null;

                var deploymentAssemblyParts =
                    DeploymentUtility.ListDeploymentAssemblyParts(e);

                foreach(var part in deploymentAssemblyParts)
                {
                    var xapInfo = new StreamResourceInfo(e.Result, "application/binary");
                    var xapUri = new Uri(part.Source, UriKind.Relative);
                    var partInfo = Application.GetResourceStream(xapInfo, xapUri);

                    var assemblyPart = new AssemblyPart();
                    if(part.Source == this._params.XapAssemblyName)
                    {
                        silverlightApplication =
                            assemblyPart.Load(partInfo.Stream);
                    }
                    else
                    {
                        assemblyPart.Load(partInfo.Stream);
                    }
                };

                if(silverlightApplication == null)
                {
                    throw (new Exception("The Silverlight application in the downloaded XAP could not be found."));
                }

                var type = silverlightApplication.GetType(
                    this._params.XapAssemblyCompositionHost, true);

                var compositionHostProperty = type.GetProperty("MefHost",
                    BindingFlags.Static | BindingFlags.Public);
                if(compositionHostProperty == null)
                    throw new NullReferenceException("The expected Composition " +
                        "Host property was not found.");

                var getRootVisual = type.GetMethod("GetRootVisual");
                if(getRootVisual == null)
                    throw new NullReferenceException("The expected Composition " +
                        "Host method was not found.");

                var compositionHost = compositionHostProperty
                    .GetValue(compositionHostProperty, Type.EmptyTypes);
                if(compositionHost == null)
                    throw new NullReferenceException("The expected Composition " +
                        "Host instance was not found.");

                var setSilverlightHost = type.GetMethod("SetSilverlightHost");
                if(setSilverlightHost == null)
                    throw new NullReferenceException("The expected Composition " +
                        "Host method was not found.");
                setSilverlightHost.Invoke(compositionHost, new object[] { this._silverlightHost });

                var rootVisual = (UserControl)getRootVisual.
                    Invoke(compositionHost, Type.EmptyTypes);
                if(rootVisual == null)
                    throw new NullReferenceException("The expected Composition " +
                        "Host Root Visual was not found.");

                this.GridOne.Children.Clear();
                this.GridOne.Children.Add(rootVisual);
            }
            catch(Exception ex)
            {
                this.LoadFailed(ex);
                return;
            }
        }

        internal void LoadFailed(Exception e)
        {
            this.Progress.Value = 0;
            this.Progress.Background =
                new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
            this.ProgressText.Text = e.Message;
        }

        internal void LoadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            this.Progress.Value = e.ProgressPercentage;
            this.ProgressText.Text =
                (e.BytesReceived / 1024) + "kb / "
                + (e.TotalBytesToReceive / 1024) + "kb";
        }

        LoaderInfo _params;
        SilverlightHost _silverlightHost;
    }
}
